package com.xuecheng.media.service.jobhandler;

import com.xuecheng.base.utils.Mp4VideoUtil;
import com.xuecheng.media.model.po.MediaProcess;
import com.xuecheng.media.service.MediaProcessService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import static com.xuecheng.media.utils.MinIOFileOperationUtils.*;

@Slf4j
@Component
public class VideoTask {
    private final MediaProcessService mediaProcessService;
    private final int CPU_CORE_NUMBER;
    private ExecutorService executorService;
    private final static long awaitTime = 5 * 1000;;
    public VideoTask(MediaProcessService mediaProcessService) {
        this.mediaProcessService = mediaProcessService;
        this.CPU_CORE_NUMBER = Runtime.getRuntime().availableProcessors();
        this.executorService = Executors.newFixedThreadPool(CPU_CORE_NUMBER);
    }
    /** 第三方插件ffmpeg的路径 **/
    @Value("${videoprocess.ffmpegpath}")
    private String ffmpegPath;

    @XxlJob("videoJobHandler")
    public void shardJobHandler() throws Exception {
        // 分片参数
        int shardIndex = XxlJobHelper.getShardIndex();
        int shardTotal = XxlJobHelper.getShardTotal();

        // 查询待处理任务
        List<MediaProcess> tasks = mediaProcessService.selectListByShardIndex(shardTotal,
                shardIndex,
                CPU_CORE_NUMBER);
        if (tasks.size() == 0) {
            log.debug("获取到的视频处理任务数: {}", 0);
            return;
        }
        CountDownLatch countDownLatch = new CountDownLatch(CPU_CORE_NUMBER);
        tasks.forEach(task -> executorService.execute(() -> {
            try {
                // 开启任务
                Long taskId = task.getId();
                String fileId = task.getFileId();
                boolean acquireLock = mediaProcessService.startTask(taskId);
                if (!acquireLock) {
                    log.debug("抢占任务失败, 任务id: {}", taskId);
                    return;
                }
                String bucketName = task.getBucket();
                String objectName = task.getFilePath();
                File file = downFileFromMinIO(bucketName
                        , objectName);
                if (Objects.isNull(file)) {
                    log.debug("下载视频文件异常: 任务id:{} bucketName:{} objectName:{}", taskId,
                            bucketName,
                            objectName);
                    mediaProcessService.updateProcessFinishStatus(taskId,
                            MEDIA_PROCESS_FAIL,
                            fileId,
                            null,
                            "下载视频文件异常");
                    return;
                }

                // 执行视频转码
                String path = file.getAbsolutePath();
                String videoName = fileId + DOT_MP4;
                File temp = null;
                try {
                    temp = File.createTempFile("minio", DOT_MP4);
                } catch (IOException e) {
                    log.error("创建临时文件异常, {}", e.getMessage());
                    mediaProcessService.updateProcessFinishStatus(taskId,
                            MEDIA_PROCESS_FAIL,
                            fileId,
                            null,
                            "创建临时文件异常");
                    return;
                }
                String mp4Path = temp.getAbsolutePath();
                Mp4VideoUtil videoUtil = new Mp4VideoUtil(ffmpegPath,
                        path,
                        videoName,
                        mp4Path);
                String success = videoUtil.generateMp4();
                if (!"success".equals(success)) {
                    log.error("视频转码失败, bucketName:{}, objectName:{}, 异常信息:{}",
                            bucketName,
                            objectName,
                            success);
                    mediaProcessService.updateProcessFinishStatus(taskId,
                            MEDIA_PROCESS_FAIL,
                            fileId,
                            null,
                            "视频转码失败");
                    return;
                }

                // 上传MinIO
                boolean uploadSuccess = uploadFileToMinio(bucketName,
                        mp4Path,
                        objectName.replaceAll(".[a-z]{3}$", DOT_MP4),
                        getMimeType(DOT_MP4));
                if (!uploadSuccess) {
                    log.error("上传文件到MinIO失败, bucketName:{}, taskId:{}, objectName:{}",
                            bucketName,
                            taskId,
                            objectName);
                    mediaProcessService.updateProcessFinishStatus(taskId,
                            MEDIA_PROCESS_FAIL,
                            fileId,
                            null,
                            "上传文件到MinIO失败");
                    return;
                }
                // mp4文件的url
                String url = getMinIOMergeFilePath(fileId, DOT_MP4);

                // 保存任务处理结果
                mediaProcessService.updateProcessFinishStatus(taskId,
                        MEDIA_PROCESS_SUCCESS,
                        fileId,
                        url,
                        null);

                // 删除本地下载的文件
                file.delete();
                temp.delete();
            } finally {
                // 计数器减1
                countDownLatch.countDown();
            }
        }));
        // 等待最多半个小时
        countDownLatch.await(30, TimeUnit.MINUTES);
    }

//    @PreDestroy
//    public void executorClose() {
//        try {
//            executorService.shutdown();
//            if(!executorService.awaitTermination(awaitTime, TimeUnit.MILLISECONDS)){
//                executorService.shutdownNow();
//            }
//        } catch (InterruptedException e) {
//            log.error("awaitTermination interrupted: " + e);
//            executorService.shutdownNow();
//        }
//    }
}
